/**
 ******************************************************************************
 * @file           : log_port.c
 * @brief          : MicroLog porting layer implementation
 * @version        : 1.1.0
 * @date           : 2025-10-18
 ******************************************************************************
 * @note  移植层实现：根据实际平台提供锁机制
 *        用户可根据需要修改此文件以适配不同的 RTOS
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "log_port.h"
#include "log.h"
#include <stdio.h>

/* 平台头文件 */
#if defined(STM32F1)
    #include "stm32f1xx_hal.h"
#elif defined(STM32F4)
    #include "stm32f4xx_hal.h"
#elif defined(STM32H7)
    #include "stm32h7xx_hal.h"
#elif defined(STM32F0)
    #include "stm32f0xx_hal.h"
#elif defined(STM32L4)
    #include "stm32l4xx_hal.h"
#endif

/* FreeRTOS 环境：包含 FreeRTOS 头文件 */
#if (LOG_ENABLE_OUTPUT_LOCK || LOG_ENABLE_TASK) && defined(USING_FREERTOS)
    #include "FreeRTOS.h"
    #include "task.h"
#endif

/* Exported functions --------------------------------------------------------*/
/**
 * @brief       移植层初始化
 *
 * @param       None
 *
 * @retval      None
 *
 * @note        用于初始化硬件资源（UART、USB等）
 *              如果使用 printf，且 HAL 库已配置好，可以为空
 */
void log_port_init(void)
{
    /* 在此添加硬件初始化代码 */
    /* 例如：初始化 UART、USB CDC 等 */
    
    /* 打印设备信息横幅（仅在初始化时打印一次）*/
    printf("\r\n");
    printf("============================================================\r\n");
    printf("              MicroLog - 轻量级日志系统              \r\n");
    printf("============================================================\r\n");
    
#if defined(STM32F1)
    printf("设备型号: STM32F1xx\r\n");
#elif defined(STM32F4)
    printf("设备型号: STM32F4xx\r\n");
#elif defined(STM32H7)
    printf("设备型号: STM32H7xx\r\n");
#elif defined(STM32F0)
    printf("设备型号: STM32F0xx\r\n");
#elif defined(STM32L4)
    printf("设备型号: STM32L4xx\r\n");
#else
    printf("设备型号: Unknown\r\n");
#endif
    
    printf("日志版本: v%d.%d.%d\r\n", LOG_VERSION_MAJOR, LOG_VERSION_MINOR, LOG_VERSION_PATCH);
    printf("编译时间: %s %s\r\n", __DATE__, __TIME__);
    
#if defined(USING_FREERTOS)
    printf("运行环境: FreeRTOS\r\n");
#else
    printf("运行环境: 裸机\r\n");
#endif
    
    printf("============================================================\r\n");
    printf("\r\n");
}

/**
 * @brief       移植层反初始化
 *
 * @param       None
 *
 * @retval      None
 *
 * @note        用于释放硬件资源
 */
void log_port_deinit(void)
{
    /* 在此添加硬件反初始化代码 */
}

/**
 * @brief       获取系统时间戳
 *
 * @param       None
 *
 * @return      当前系统时间戳（毫秒）
 *
 * @note        用于日志时间戳显示
 */
#if LOG_ENABLE_TIMESTAMP
uint32_t log_port_get_tick(void)
{
#if defined(STM32F1) || defined(STM32F4) || defined(STM32H7) || defined(STM32F0) || defined(STM32L4)
    return HAL_GetTick();
#else
    /* 其他平台，用户需自行实现 */
    return 0;
#endif
}
#endif

/**
 * @brief       获取当前任务名称
 *
 * @param       None
 *
 * @return      任务名称字符串
 *
 * @note        FreeRTOS 环境下返回当前任务名，裸机环境返回 "Main"
 */
#if LOG_ENABLE_TASK
const char* log_port_get_task_name(void)
{
#if defined(USING_FREERTOS)
    TaskHandle_t current_task = xTaskGetCurrentTaskHandle();
    if (current_task != NULL)
    {
        return pcTaskGetName(current_task);
    }
    return "Unknown";
#else
    return "Main";
#endif
}
#endif

/**
 * @brief       底层输出函数
 *
 * @param[in]   log: 日志内容指针
 * @param[in]   size: 日志内容长度
 *
 * @retval      None
 *
 * @note        用户可根据平台修改此函数，输出到 UART/USB/文件等
 *              默认使用 printf（需要配置好 HAL 库的重定向）
 */
void log_port_output(const char *log, size_t size)
{
    /* 默认使用 printf，指定长度输出 */
    printf("%.*s", (int)size, log);
    
    /* 或者使用 UART 直接输出 */
    // HAL_UART_Transmit(&huart1, (uint8_t*)log, size, 1000);
    
    /* 或者使用 USB CDC */
    // CDC_Transmit_FS((uint8_t*)log, size);
}

/**
 * @brief       刷新输出缓冲区
 *
 * @param       None
 *
 * @retval      None
 *
 * @note        确保所有日志都被输出
 *              - printf 使用 fflush(stdout)
 *              - UART 一般不需要（直接发送）
 *              - USB CDC 可能需要等待发送完成
 */
void log_port_flush(void)
{
    /* printf 重定向到 UART 时，不需要刷新缓冲区 */
    /* 注意：fflush(stdout) 会引入标准库符号，可能导致链接冲突 */
    
    /* printf 环境（如果需要）：刷新缓冲区 */
    // fflush(stdout);
    
    /* UART 直接发送：不需要刷新 */
    
    /* USB CDC 环境：等待发送完成 */
    // 可以添加 CDC_WaitUntilReady() 等待
}

#if LOG_ENABLE_OUTPUT_LOCK
/**
 * @brief       输出锁定（进入临界区）
 *
 * @param       None
 *
 * @retval      None
 *
 * @note        多线程环境下保护日志输出的原子性
 */
void log_port_lock(void)
{
#if defined(USING_FREERTOS)
    /* FreeRTOS 环境：进入临界区 */
    taskENTER_CRITICAL();
    
#elif defined(USING_RTTHREAD)
    /* RT-Thread 环境：进入临界区 */
    rt_enter_critical();
    
#else
    /* 裸机环境：关闭全局中断（示例，根据实际芯片调整）*/
    __disable_irq();  /* ARM Cortex-M */
#endif
}

/**
 * @brief       输出解锁（退出临界区）
 *
 * @param       None
 *
 * @retval      None
 *
 * @note        与 log_port_lock() 成对使用
 */
void log_port_unlock(void)
{
#if defined(USING_FREERTOS)
    /* FreeRTOS 环境：退出临界区 */
    taskEXIT_CRITICAL();
    
#elif defined(USING_RTTHREAD)
    /* RT-Thread 环境：退出临界区 */
    rt_exit_critical();
    
#else
    /* 裸机环境：开启全局中断（示例，根据实际芯片调整）*/
    __enable_irq();  /* ARM Cortex-M */
#endif
}

#endif /* LOG_ENABLE_OUTPUT_LOCK */

